{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Netzwerke modellieren mit pandapipes"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Diese Einführung stellt die von pandapipes genutzten Datenstrukturen vor und zeigt, wie mit Hilfe der pandapipes API Netzwerke erstellt werden können. Das folgende Beispiel enthält die gängigsten Komponenten, die im Rahmen von pandapipes eingesetzt werden.\n",
    "\n",
    "<img src=\"pics/simple_network-1.png\">\n",
    "\n",
    "Die pandapipes-Umgebung basiert auf der Python-Bibliothek \"pandas\". Ein Netzwerk enthält Tabellen für jeden Komponententyp, der eingesetzt wird. Die Zeilen der Tabellen entsprechen den tatsächlich im Netzwerk vorhandenen Komponenten. Jede Zeile in einer Komponententabelle repräsentiert also eine Komponente des jeweiligen Typs. Die Spalten entsprechen den Eigenschaften des Komponententyps.\n",
    "\n",
    "Durch das Ausführen der folgenden Code-Zellen des Notebooks werden die für das betrachtete Netz benötigten Komponententabellen erstellt. Wenn Sie weitere Informationen zu den einzelnen Parametern der Komponenten benötigen, so finden Sie diese in der pandapipes-Dokumentation unter Punkt \"Datastructure and Components\".\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Leeres Netzwerk"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Zunächst wird pandapipes importiert und ein leeres Netzwerk erzeugt:\n",
    "\n",
    "Für jede Berechnung ist es wichtig, ein Transportmedium auszuwählen. Obwohl auch eigene Fluide definiert werden können, greifen wir im Rahmen dieses Tutorials auf die Fluidbibliothek zurück. Ein Fluid wird über die Angabe des entsprechenden Namens aus der Bibliothek geladen. Namenskürzel sind z.B.  <span style=\"color:green\">hgas</span>, <span style=\"color:green\">lgas</span>,  <span style=\"color:green\">hydrogen</span>,\n",
    "<span style=\"color:green\">water</span>, und <span style=\"color:green\">air</span>.\n",
    "\n",
    "Da wir ein Erdgasnetz erzeugen wollen, wählen wir <span style=\"color:green\">lgas</span> aus der Bibliothek aus."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "scrolled": true
   },
   "outputs": [],
   "source": [
    "import pandapipes as pp"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "net = pp.create_empty_network(fluid=\"lgas\") # create an empty network"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "An diesem Punkt enthält das Netz noch keinerlei Komponenten. Es dient aber als ein Container für die Komponententabellen und netzwerkspezifische Parameter."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "net"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Die <span style=\"color:blue\">create</span>-Funktionen werden nun eingesetzt, um neue Komponenten zu erzeugen. Diese werden automatisch den entsprechenden Tabellen hinzugefügt. "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Junctions"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<img src=\"pics/simple_network-junc.png\">\n",
    "\n",
    "In einem ersten Schritt werden die Knotenpunkte des Netzwerks erstellt, zwischen denen Rohrleitungen und andere Komponenten verlaufen. Diese Knotenpunkte werden \"junctions\" genannt. Insgesamt werden davon sechs benötigt. Für jeden Knotenpunkt wird zudem ein Anfangswert benötigt. Bei diesem handelt es sich um einen initialen Schätzwert, der im Laufe der Berechnung angepasst und am Ende durch das Berechnungsergebnis ersetzt wird. Der Anfangswert beträgt 1.0 bar.\n",
    "\n",
    "Außerdem wird eine Temperatur für das Fluid definiert. Diese wird für die hydraulischen Berechnungen benötigt.\n",
    "\n",
    "Das Vergeben von Namen ist optional, erhöht aber die Lesbarkeit der Ergebnisse. \n",
    "\n",
    "Diese Werte werden als Parameter der create_junction-Funktion übergeben."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "junction1 = pp.create_junction(net, pn_bar=1.0, tfluid_k=293.15, name=\"Connection to External Grid\")\n",
    "junction2 = pp.create_junction(net, pn_bar=1.0, tfluid_k=293.15, name=\"Junction 2\")\n",
    "junction3 = pp.create_junction(net, pn_bar=1.0, tfluid_k=293.15, name=\"Junction 3\")\n",
    "junction4 = pp.create_junction(net, pn_bar=1.0, tfluid_k=293.15, name=\"Junction 4\")\n",
    "junction5 = pp.create_junction(net, pn_bar=1.0, tfluid_k=293.15, name=\"Junction 5\")\n",
    "junction6 = pp.create_junction(net, pn_bar=1.0, tfluid_k=293.15, name=\"Junction 6\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Die definierten Knoten befinden sich jetzt im Netz-Container und können abgerufen werden. Einigen Parametern, die beim Funktionsaufruf nicht explizit erwähnt worden sind, wurden Standardwerte zugewiesen."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "net.junction # show junction table"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Alle create-Funktionen geben den pandapipes-Index des Elements zurück, welches erzeugt wurde. Beispielsweise entspricht die Variable \"junction1\" dem Index des Knoten mit dem Namen \"Connection to External Grid\". Der Index ist entsprechend 0."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "junction1"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "net.junction.loc[junction1]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Wir nutzen diese Variablen im Folgenden, um Komponenten, wie z.B. Rohre, mit den Knoten zu verbinden."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### External Grid"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<img src=\"pics/simple_network-ext_grid.png\">\n",
    "\n",
    "Ein External Grid repräsentiert eine mögliche Schnittstelle zum einem Netzbereich, der vom pandapipes-Modell nicht erfasst wird. Mathematisch gesehen wird der Druck an dem Knoten, an dem das External Grid angeschlossen ist, während der Berechnung nicht mehr angepasst. Sie teilen dem Programm damit mit, dass Ihnen der Wert des Druckes an dieser Stelle bereits bekannt ist. Für eine erfolgreiche Berechnung ist die Bekanntgabe eines festen Druckwertes an wenigstens einer Position im Netz unbedingt notwendig. Das External Grid erfüllt mit diesen Eigenschaften die Funktions eines slack-Knotens.\n",
    "\n",
    "in unserem Beispiel wird das External Grid mit der Junction-Variable junction1 verbunden. Der Druck beträgt 1.1 bar. In der späteren Auswertung wird der Druck, den Sie an junction1 abrufen, folglich ebenfalls 1.1 bar betragen.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "medium_pressure_grid = pp.create_ext_grid(net, junction=junction1, p_bar=1.1, t_k=293.15, name=\"Grid Connection\")\n",
    "\n",
    "net.ext_grid # show external grid table"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Rohre"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Das Netzwerk enthält 5 Rohre, die zwischen je zwei Knoten verlaufen. Die Verbindungspunkte und die jeweiligen Rohrlängen sind im Diagramm zu sehen:\n",
    "\n",
    "<img src=\"pics/simple_network-pipes.png\">\n",
    "\n",
    "Alle Rohre haben einen Durchmesser von 300 mm. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "pipe1 = pp.create_pipe_from_parameters(net, from_junction=junction1, to_junction=junction2, length_km=10, diameter_m=0.3, name=\"Pipe 1\")\n",
    "pipe2 = pp.create_pipe_from_parameters(net, from_junction=junction2, to_junction=junction3, length_km=2, diameter_m=0.3, name=\"Pipe 2\")\n",
    "pipe3 = pp.create_pipe_from_parameters(net, from_junction=junction2, to_junction=junction4, length_km=2.5, diameter_m=0.3, name=\"Pipe 3\")\n",
    "pipe4 = pp.create_pipe_from_parameters(net, from_junction=junction3, to_junction=junction5, length_km=1, diameter_m=0.3, name=\"Pipe 4\")\n",
    "pipe5 = pp.create_pipe_from_parameters(net, from_junction=junction4, to_junction=junction6, length_km=1, diameter_m=0.3, name=\"Pipe 5\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Damit sieht die Tabelle der Rohrkomponenten wie folgt aus:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "net.pipe # show pipe table"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Die Parameter from_junction und to_junction geben die Orientierung des Rohrs an. Wenn die Flussrichtung tatsächlich aus Richtung from_junction in Richtung to_junction verläuft, ist das Vorzeichen der berechneten Strömungsgeschwindigkeit positiv. Andernfalls nimmt die Strömungsgeschwindigkeit negative Werte an."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Ventil"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Es gibt ein Ventil zwischen Junction 5 und Junction 6. Dieses ist geöffnet, sodass das Gas das Ventil passieren kann.\n",
    "\n",
    "<img src=\"pics/simple_network-valve.png\">"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "valve = pp.create_valve(net, from_junction=junction5, to_junction=junction6, diameter_m=0.3, opened=True)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Wie man sieht, wird standardmäßig kein Druckverlustkoeffizient für das Ventil angegeben. Außerdem haben Ventile keine Länge. Der Druckverlustkoeffizient kann bei Bedarf modifiziert werden."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "net.valve # show valve table"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Senke\n",
    "\n",
    "<img src=\"pics/simple_network-sink.png\">"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Mit Hilfe einer Senke kann eine konstante Abnahme, wie bspw. einer KWK-Anlage, definiert werden. An dieser Stelle wird eine sink-Komponente mit einem Massestrom in Höhe von 545 g/s definiert. Senken und Quellen werden immer einem bestimmten Knoten zugeordnet. Das Vorzeichen des Massestroms ist positiv, wenn ein Massestrom aus dem System entnommen wird.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "sink = pp.create_sink(net, junction=junction4, mdot_kg_per_s=0.545, name=\"Sink 1\")\n",
    "net.sink"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Quelle\n",
    "\n",
    "<img src=\"pics/simple_network-source.png\">"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Die Source-Komponente wird genutzt, um einen Wärme- oder Massestrom in das Netz einzuspeisen. Ein denkbarer Fall ist der einer Biogas- oder P2G-Anlage, welche direkt an das Gasnetz angeschlossen ist. \n",
    "\n",
    "In diesem Beispiel nehmen wir an, dass eine Biogasanlage direkt ins Gasnetz einspeist. Die Anlage liefert einen konstanten Strom in Höhe von 234 g/s. Aus Sicht der Source-Komponente ist das Vorzeichen positiv, wenn ins System eingespeist wird."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "source = pp.create_source(net, junction=junction3, mdot_kg_per_s=0.234, name=\"Source 1\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "net.source"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Die Modellierung des Netzes ist damit abgeschlossen. Abschließend können alle Komponenten des Netzes angezeigt werden."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "net"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Die eigentliche Berechnung wird mit dem `pipeflow`-Kommando gestartet:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "pycharm": {
     "name": "#%%\n"
    }
   },
   "outputs": [],
   "source": [
    "pp.pipeflow(net)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "pycharm": {
     "name": "#%% md\n"
    }
   },
   "source": [
    "Ergebnisse werden in Tabellen mit dem Präfix `res_...` gespeichert. Auch diese Tabellen sind nach der Berechnung im  `net`-Container abgelegt. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "pycharm": {
     "name": "#%%\n"
    }
   },
   "outputs": [],
   "source": [
    "net # result tables have been added to the net "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "pycharm": {
     "name": "#%%\n"
    }
   },
   "outputs": [],
   "source": [
    "net.res_junction # calculated pressure and temperature at junctions"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "pycharm": {
     "name": "#%%\n"
    }
   },
   "outputs": [],
   "source": [
    "net.res_pipe  # velocities, mass flows through pipes and other results"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.4"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
